<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
  /***
   * 数据访问对象模式（DAO）
   * 因为在前端，一般使用的是localStorage
   * 但是在localStorage里面是没有限制的，
   * 这意味着每个人都可以随意操作它，所以我们需要一个类来限制他
   *
   * 数据范文对象模式是一种对数据库的操作（如简单的CRUD创建，读取，更新，删除）
   * 进行封装，用户不必为操作数据库感到烦恼，DAO已经为我们准备好了简单而统一的操作接口
   *
   ***/

  /***
   * 本地存储类
   * 参数：preId   本地存储数据库前缀
   * 参数：timeSign    时间戳与存储数据之间的拼接符
   ***/
  let BaseLocalStorage = function (preId,timeSign){
  //  定义本地数据库前缀
    this.preId = preId;
  //  定义本地时间戳与存储数据之间的拼接符
    this.timeSign = timeSign;
  }
//  本地存储类原型
  BaseLocalStorage.prototype = {
  //  操作状态
    status:{
      SUCCESS:0,//成功
      FAILURE:1,//失败
      OVERFLOW:2,//溢出
      TIMEOUT:3,//过期
    },
  //  保存本地存储链接
    storage: localStorage || window.localStorage,
  //  获取本地存储数据数据真实字段
    getKey :function (key) {
      return this.preId + key;
    },
    /***
     * 添加（修改数据）
     * 参数：key   数据字段标识
     * 参数：value   数据值
     * 参数：callback   回调函数
     * 参数：time   添加时间
     ***/
    set : function (key,value,callback,time){
      //  默认操作状态成功
      let status = this.status.SUCCESS;
      //    获取真实字段
      let currentKey = this.getKey(key);
      try{
        //  参数时间参数时获取时间戳
        time = new Date(time).getTime() || time.getTime();
      }catch (e){
        //  如果出现错误，默认参数有效时间为一个月
        time = new Date().getTime() + 1000 * 60 * 24 * 31;
      }
      try{
        //  向数据库中添加数据
        this.storage.setItem(currentKey,time+this.timeSign + value);
      }catch (e){
        //  溢出失败
        status = this.status.OVERFLOW;
      }
      //  有回调函数就执行回调函数并传入参数操作状态，真实数据字段标识以及存储数据值
      callback && callback.call(this,status,currentKey,value);
    },
    /***
     * 获取数据
     * 参数：key   数据字段标识
     * 参数：callback   回调函数
     ***/
    get : function (key,callback) {
        //默认操作状态成功
        let status = this.status.SUCCESS;
        //获取当前数据的字段
        let currentKey = this.getKey();
        let value = null;
        //时间戳与存储数据之间的拼接符长度
        let timeSignLen = this.timeSign.length;
        //缓存当前对象
        let that = this;
        //时间戳与存储数据之间的拼接符起始位置
        let index;
        //时间戳
        let time ;
        //最后得到的数据
        let result;
      try{
      //  获取当前字段对应的数据字符串
        value = that.storage.getItem(currentKey);
      }catch (e){
      //  获取失败则返回失败状态，数据结果为null
        result = {
          status : that.status.FAILURE,
          value : null
        };
      //  执行回调并返回
        callback && callback.call(this,result.status,result.value)
        return result;
      }
    //  如果成果获取数据字符串
      if(value){
      //  获取时间戳与存储数据之间的拼接符起始位置
        index = value.indexOf(that.timeSign);
      //  获取时间戳
        time = +value.slice(0,index);
      //  如果时间为过期
        if(new Date(time).getTime() > new Date().getTime() || time === 0){
          value = value.slice(index + timeSignLen);
        }else{
        //  过期则结果为null
          value = null;
        //  设置状态为过期状态
          status = that.status.TIMEOUT;
        //  删除该字段
          that.remove(key);
        }
      }else{
      //  未获取数据字符串状态为失败状态
        status = that.status.FAILURE;
      }
    //设置结果
      result = {
        status : status,
        value : value
      }
      //  执行回调并返回
      callback && callback.call(this,result.status,result.value)
      return result;
    },
    /***
     * 删除数据
     * 参数：key   数据字段标识
     * 参数：callback   回调函数
     ***/
    remove : function (key,callback) {
      //  默认操作状态成功
      let status = this.status.FAILURE;
      //    获取真实字段
      let currentKey = this.getKey(key);
      //设置默认数据为空
      let value = null;
      try{
        //  获取字段对应的数据
        value = this.storage.getItem(currentKey);
      }catch (e){}
      if(value){
        try{
        //  删除数据
          this.storage.removeItem(currentKey)
        //  设置操作成功
          status = this.status.SUCCESS
        }catch (e){}
      }
      //  有回调函数就执行回调函数并传入参数操作状态，真实数据字段标识以及存储数据值
      callback && callback.call(
        this,
        status,
        status > 0 ? null : value.slice(value.indexOf(this.timeSign) + this.timeSign.length)
      );
    }
  }
  let LS = new BaseLocalStorage('LS__','###')
  LS.set('a','yjm',function (){
    console.log(arguments);
  })
  LS.get('a',function (){
    console.log(arguments)
  })
  LS.remove('a',function (){
    console.log(arguments)
  })
  LS.get('a',function (){
    console.log(arguments)
  })

</script>
</body>
</html>
